#ifndef WRAP_FCNTL_H
#define WRAP_FCNTL_H

namespace Wrap {

int o_rdonly();
int o_rdwr();
int o_noctty();
int o_nonblock();
int o_cloexec();

/// @see https://man7.org/linux/man-pages/man2/fcntl.2.html
/// @param fd fcntl() performs one of the operations described below on the
/// open file descriptor @c fd.
/// @param cmd The operation is determined by @c cmd.
/// @return For a successful call, the return value depends on the operation.
/// On error, -1 is returned, and errno is set to indicate the error.
/// @throw EACCES Operation is prohibited by locks held by other processes.
/// @throw EAGAIN Operation is prohibited by locks held by other processes.
/// @throw EAGAIN The operation is prohibited because the file has been
/// memory-mapped by another process.
/// @throw EBADF @c fd is not an open file descriptor
/// @throw EBADF @c cmd is F_SETLK or F_SETLKW and the file descriptor open mode
/// doesn't match with the type of lock requested.
/// @throw EBUSY @c cmd is F_SETPIPE_SZ and the new pipe capacity specified in
/// @c ...arg is smaller than the amount of buffer space currently used to store
/// data in the pipe.
/// @throw EBUSY @c cmd is F_ADD_SEALS, @c ...arg includes F_SEAL_WRITE, and
/// there exists a writable, shared mapping on the file referred to by @c fd.
/// @throw EDEADLK It was detected that the specified F_SETLKW command would
/// cause a deadlock.
/// @throw EFAULT lock is outside your accessible address space.
/// @throw EINTR @c cmd is F_SETLKW or F_OFD_SETLKW and the operation was
/// interrupted by a signal; see signal(7).
/// @throw EINTR @c cmd is F_GETLK, F_SETLK, F_OFD_GETLK, or F_OFD_SETLK, and
/// the operation was interrupted by a signal before the lock was checked or
/// acquired.  Most likely when locking a remote file (e.g., locking over NFS),
/// but can sometimes happen locally.
/// @throw EINVAL The value specified in @c cmd is not recognized by this
/// kernel.
/// @throw EINVAL @c cmd is F_ADD_SEALS and @c ...arg includes an unrecognized
/// sealing bit.
/// @throw EINVAL @c cmd is F_ADD_SEALS or F_GET_SEALS and the filesystem
/// containing the inode referred to by @c fd does not support sealing.
/// @throw EINVAL @c cmd is F_DUPFD and @c ...arg is negative or is greater than
/// the maximum allowable value (see the discussion of RLIMIT_NOFILE in
/// getrlimit(2)).
/// @throw EINVAL @c cmd is F_SETSIG and @c ...arg is not an allowable signal
/// number.
/// @throw EINVAL @c cmd is F_OFD_SETLK, F_OFD_SETLKW, or F_OFD_GETLK, and l_pid
/// was not specified as zero.
/// @throw EMFILE @c cmd is F_DUPFD and the per-process limit on the number of
/// open file descriptors has been reached.
/// @throw ENOLCK Too many segment locks open, lock table is full, or a remote
/// locking protocol failed (e.g., locking over NFS).
/// @throw ENOTDIR F_NOTIFY was specified in @c cmd, but @c fd does not refer to
/// a directory.
/// @throw EPERM @c cmd is F_SETPIPE_SZ and the soft or hard user pipe limit has
/// been reached; see pipe(7).
/// @throw EPERM Attempted to clear the O_APPEND flag on a file that has the
/// append-only attribute set.
/// @throw EPERM @c cmd was F_ADD_SEALS, but @c fd was not open for writing or
/// the current set of seals on the file already includes F_SEAL_SEAL.
int fcntl_(int fd, int cmd, ...);

/// @see https://man7.org/linux/man-pages/man2/open.2.html
/// @return On success, open() return the new file descriptor (a nonnegative
/// integer). On error, -1 is returned and errno is set to indicate the error.
/// @throw EACCES The requested access to the file is not allowed, or search
/// permission is denied for one of the directories in the path prefix of @c
/// path, or the file did not exist yet and write access to the parent directory
/// is not allowed.  (See also path_resolution(7).)
/// @throw EACCES Where O_CREAT is specified, the protected_fifos or
/// protected_regular sysctl is enabled, the file already exists and is a FIFO
/// or regular file, the owner of the file is neither the current user nor the
/// owner of the containing directory, and the containing directory is both
/// world- or group-writable and sticky.  For details, see the descriptions of
/// /proc/sys/fs/protected_fifos and /proc/sys/fs/protected_regular in proc(5).
/// @throw EBUSY O_EXCL was specified in @c flag and @c path refers to a block
/// device that is in use by the system (e.g., it is mounted).
/// @throw EDQUOT Where O_CREAT is specified, the file does not exist, and the
/// user's quota of disk blocks or inodes on the filesystem has been exhausted.
/// @throw EEXIST @c path already exists and O_CREAT and O_EXCL were used.
/// @throw EFAULT @c path points outside your accessible address space.
/// @throw EFBIG See EOVERFLOW.
/// @throw EINTR While blocked waiting to complete an open of a slow device
/// (e.g., a FIFO; see fifo(7)), the call was interrupted by a signal handler;
/// see signal(7).
/// @throw EINVAL The filesystem does not support the O_DIRECT flag.  See NOTES
/// for more information.
/// @throw EINVAL Invalid value in @c flag.
/// @throw EINVAL O_TMPFILE was specified in @c flag, but neither O_WRONLY nor
/// O_RDWR was specified.
/// @throw EINVAL O_CREAT was specified in @c flag and the final component
/// ("basename") of the new file's @c path is invalid (e.g., it contains
/// characters not permitted by the underlying filesystem).
/// @throw EINVAL The final component ("basename") of @c path is invalid (e.g.,
/// it contains characters not permitted by the underlying filesystem).
/// @throw EISDIR @c path refers to a directory and the access requested
/// involved writing (that is, O_WRONLY or O_RDWR is set).
/// @throw EISDIR @c path refers to an existing directory, O_TMPFILE and one of
/// O_WRONLY or O_RDWR were specified in @c flag, but this kernel version does
/// not provide the O_TMPFILE functionality.
/// @throw ELOOP Too many symbolic links were encountered in resolving @c path.
/// @throw ELOOP @c path was a symbolic link, and @c flag specified O_NOFOLLOW
/// but not O_PATH.
/// @throw EMFILE The per-process limit on the number of open file descriptors
/// has been reached (see the description of RLIMIT_NOFILE in getrlimit(2)).
/// @throw ENAMETOOLONG @c path was too long.
/// @throw ENFILE The system-wide limit on the total number of open files has
/// been reached.
/// @throw ENODEV @c path refers to a device special file and no corresponding
/// device exists.  (This is a Linux kernel bug; in this situation ENXIO must be
/// returned.)
/// @throw ENOENT O_CREAT is not set and the named file does not exist.
/// @throw ENOENT A directory component in @c path does not exist or is a
/// dangling symbolic link.
/// @throw ENOENT @c path refers to a nonexistent directory, O_TMPFILE and one
/// of O_WRONLY or O_RDWR were specified in @c flag, but this kernel version
/// does not provide the O_TMPFILE functionality.
/// @throw ENOMEM The named file is a FIFO, but memory for the FIFO buffer can't
/// be allocated because the per-user hard limit on memory allocation for pipes
/// has been reached and the caller is not privileged; see pipe(7).
/// @throw ENOMEM Insufficient kernel memory was available.
/// @throw ENOSPC @c path was to be created but the device containing @c path
/// has no room for the new file.
/// @throw ENOTDIR A component used as a directory in @c path is not, in fact, a
/// directory, or O_DIRECTORY was specified and @c path was not a directory.
/// @throw ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no
/// process has the FIFO open for reading.
/// @throw ENXIO The file is a device special file and no corresponding device
/// exists.
/// @throw ENXIO The file is a UNIX domain socket.
/// @throw EOPNOTSUPP The filesystem containing @c path does not support
/// O_TMPFILE.
/// @throw EOVERFLOW @c path refers to a regular file that is too large to be
/// opened.  The usual scenario here is that an application compiled on a 32-bit
/// platform without -D_FILE_OFFSET_BITS=64 tried to open a file whose size
/// exceeds (1<<31)-1 bytes; see also O_LARGEFILE above.  This is the error
/// specified by POSIX.1; in kernels before 2.6.24, Linux gave the error EFBIG
/// for this case.
/// @throw EPERM  The O_NOATIME flag was specified, but the effective user ID of
/// the caller did not match the owner of the file and the caller was not
/// privileged.
/// @throw EPERM The operation was prevented by a file seal; see fcntl(2).
/// @throw EROFS  @c path refers to a file on a read-only filesystem and write
/// access was requested.
/// @throw ETXTBSY @c path refers to an executable image which is currently
/// being executed and write access was requested.
/// @throw ETXTBSY @c path refers to a file that is currently in use as a swap
/// file, and the O_TRUNC flag was specified.
/// @throw ETXTBSY @c path refers to a file that is currently being read by the
/// kernel (e.g., for module/firmware loading), and write access was requested.
/// @throw EWOULDBLOCK The O_NONBLOCK flag was specified, and an incompatible
/// lease was held on the file (see fcntl(2)).
int open_(const char *path, int flag);

}

#endif